<?php

namespace app\third\model;

use app\model\AgentSalesman;
use app\model\MobileSupplier;
use think\facade\Db;
use think\facade\Request;
use app\common\model\FinanceStat;

class Mobile
{
    /**
     * 充值面额.
     */
    private $amountMap = [
        30, 50, 100, 200,
    ];

    /**
     * 创建订单[预充].
     */
    public function createOrder($params)
    {
        $fields = [
            'mobile', 'amount', 'out_order_id', 'notify_url',
        ];
        foreach ($fields as $field) {
            if (empty($params[$field])) {
                return fail('缺少参数 ' . $field, CODE_MISS_PARAM);
            }
        }
        if (!checkMobile($params['mobile'])) {
            return fail('手机号码格式有误', CODE_MOBILE_ERROR);
        }
        $params['amount'] = intval($params['amount']);
        if (!in_array($params['amount'], $this->amountMap)) {
            return fail('充值金额有误。只能是 30, 50, 100, 200', CODE_MOBILE_AMOUNT_ERROR);
        }

        $blackList = [
            '13967196165',
        ];
        if (in_array($params['mobile'], $blackList)) {
            return fail('号码异常，无法充值', CODE_MOBILE_ERROR);
        }

        $order = Db::name('mobile_order')
            ->field('id')
            ->where('out_order_id', $params['out_order_id'])
            ->where('agent_id', $params['agent']['id'])
            ->find();
        if (!empty($order)) {
            return fail('订单已存在', CODE_ORDER_EXISTS);
        }
        if (mb_strlen($params['out_order_id']) > 32) {
            return fail('out_order_id 不能超过 32 个字符', CODE_ERROR);
        }
        if (mb_strlen($params['notify_url']) > 100) {
            return fail('notify_url 不能超过 100 个字符', CODE_ERROR);
        }

        $ispType = getMobileIsp($params['mobile']);
        // 不同运营商，话费折扣不一样
        $config = Db::name('agent_service_config')
            ->field('discount_slow, discount_fast, discount_slow_all, discount_fast_all')
            ->where('agent_id', $params['agent']['id'])
            ->where('serv_type', PRODUCT_MOBILE_SERV)
            ->find();
        if (empty($config)) {
            return fail('产品配置异常，请联系管理员。' . __LINE__);
        }
        $config['discount_slow_all'] = json_decode($config['discount_slow_all'], true);
        $config['discount_fast_all'] = json_decode($config['discount_fast_all'], true);

        if (!empty($params['is_fast'])) {
            if (1 != $params['is_fast']) {
                return fail('is_fast 有误【' . $params['is_fast'] . '】');
            }
            // 快充
            $orderType = 2;
            $settleDiscount = $config['discount_fast_all'][$ispType] ?? $config['discount_fast'];
        } else {
            // 慢充
            $orderType = 1;
            $settleDiscount = $config['discount_slow_all'][$ispType] ?? $config['discount_slow'];
        }
        $settlePrice = intval(strval($params['amount'] * $settleDiscount));

        // 筛选话费供应商 -- start todo 放 redis 缓存，加快速度
        // 指定的供应商
        $usedSupplierIds = Db::name('agent_mobile_supplier')
            ->where('agent_id', $params['agent']['id'])
            ->column('mobile_supplier_id');
        // 供应商信息
        // $supplierList = MobileSupplier::whereIn('id', $usedSupplierIds)->column('*', 'id');
        $supplierList = Db::name('mobile_supplier')
            ->whereIn('id', $usedSupplierIds)
            ->column('discount_slow, discount_fast, discount_slow_all, discount_fast_all', 'id');
        foreach ($supplierList as $k => $v) {
            $supplierList[$k]['discount_slow_all'] = json_decode($v['discount_slow_all'], true);
            $supplierList[$k]['discount_fast_all'] = json_decode($v['discount_fast_all'], true);
        }

        $map = [
            1 => 'yidong',
            2 => 'liantong',
            3 => 'dianxin',
            -1 => 'other',
        ];
        // $ispType = getMobileIsp($params['mobile']);
        $fieldName = $map[$ispType];
        if (1 == $orderType) {
            $fieldName .= '_slow';
        } else {
            $fieldName .= '_fast';
        }
        $filename = root_path() . '/data/mobileSupplierPriority.json';
        $priority = file_get_contents($filename);
        $priority = json_decode($priority, true);
        if (empty($priority) || empty($priority[$fieldName][$params['amount']])) {
            return fail('充值面额维护中');
        }
        $tmp = $priority[$fieldName][$params['amount']];
        // todo 待优化
        $supplier = [];
        foreach ($tmp as $id => $num) {
            if (!in_array($id, $usedSupplierIds)) {
                continue;
            }
            $supplier = array_merge($supplier, array_fill(0, $num, $id));
        }
        if (empty($supplier)) {
            return fail('充值通道维护中');
        }
        $max = count($supplier) - 1;
        $index = random_int(0, $max);
        $mobileSupplierId = $supplier[$index];
        unset($supplier);
        unset($priority);
        // 筛选话费供应商 -- end

        $orderId = generateMobileOrderId();
        if (false === $orderId) {
            return fail('订单号生成失败，请重试', CODE_GENERATE_ORDER_FAIL);
        }

        // 供应商折扣相关计算
        if (2 == $orderType) {
            $supplierDiscount = $supplierList[$mobileSupplierId]['discount_fast_all'][$ispType] ?? $supplierList[$mobileSupplierId]['discount_fast'];
        } else {
            $supplierDiscount = $supplierList[$mobileSupplierId]['discount_slow_all'][$ispType] ?? $supplierList[$mobileSupplierId]['discount_slow'];
        }
        $supplierPrice = intval(strval($params['amount'] * $supplierDiscount));
        $platformProfit = $settlePrice - $supplierPrice;
        $agentProfit = 0;

        Db::startTrans();
        try {
            $balance = Db::name('agent')
                ->where('id', $params['agent']['id'])
                ->lock(true)
                ->value('balance');

            if ($balance < $settlePrice) {
                Db::rollback();
                return fail('账户余额不足，请及时充值', CODE_LACK_OF_BALANCE);
            }
            $res = Db::name('agent')
                ->where('id', $params['agent']['id'])
                ->where('balance', '>=', $settlePrice)
                ->dec('balance', $settlePrice)
                ->update([
                    'balance_last_updated_at' => date('Y-m-d H:i:s'),
                ]);
            if (!$res) {
                Db::rollback();

                return fail('账户余额不足，请及时充值。' . __LINE__, CODE_LACK_OF_BALANCE);
            }
            $salesmanId = AgentSalesman::getSalesmanIdByAgentId($params['agent']['id'], PRODUCT_MOBILE_SERV);
            $id = Db::name('mobile_order')
                ->insertGetId([
                    'agent_id' => $params['agent']['id'],
                    'order_id' => $orderId,
                    'sub_order_id' => $orderId,
                    'out_order_id' => $params['out_order_id'],
                    'mobile' => $params['mobile'],
                    'amount' => yuan2fen($params['amount']),
                    'status' => 2,
                    'sale_discount' => $settleDiscount,
                    'settle_discount' => $settleDiscount,
                    'sale_price' => $settlePrice,
                    'settle_price' => $settlePrice,
                    'supplier_discount' => $supplierDiscount,
                    'supplier_price' => $supplierPrice,
                    'platform_profit' => $platformProfit, // 平台利润
                    'profit' => $agentProfit,
                    'settle_type' => SETTLE_TYPE_PREPAY, // 预充
                    'order_type' => $orderType,
                    'order_from' => ORDER_FROM_API,
                    'notify_url' => $params['notify_url'],
                    'mobile_supplier_id' => $mobileSupplierId,
                    'salesman_id' => $salesmanId,
                ]);
            Db::name('agent_balance_log')
                ->insert([
                    'agent_id' => $params['agent']['id'],
                    'type' => BALANCE_MOBILE_RECHARGE,
                    'amount' => -$settlePrice,
                    'old_balance' => $balance,
                    'new_balance' => $balance - $settlePrice,
                    'remark' => '话费充值：' . $params['amount'] . '元，结算价：' . fen2yuan($settlePrice) . '元。订单号：' . $orderId,
                    'quote_id' => $id,
                    'trade_no' => $orderId,
                ]);

            Db::commit();
        } catch (\Exception $e) {
            Db::rollback();

            doLog('api接口下单失败：' . $e->getMessage(), 'error');
            return fail('下单失败，请重试', CODE_SYSTEM_ERROR);
        }

        return success('下单成功', [
            'order_id' => $orderId,
            'out_order_id' => $params['out_order_id'],
            'amount' => $params['amount'],
            'settle_price' => fen2yuan($settlePrice),
        ]);
    }

    /**
     * 创建订单[返佣].
     */
    public function createRebateOrder($params)
    {
        $fields = [
            'mobile', 'amount', 'out_order_id', 'notify_url', 'sale_price', 'pay_type',
        ];
        foreach ($fields as $field) {
            if (empty($params[$field])) {
                return fail('缺少参数 ' . $field, CODE_MISS_PARAM);
            }
        }
        if (!in_array($params['pay_type'], [PAY_WEIXIN, PAY_ALIPAY])) {
            return fail('支付方式有误');
        }

        if (!checkMobile($params['mobile'])) {
            return fail('手机号码格式有误', CODE_MOBILE_ERROR);
        }
        $params['amount'] = intval($params['amount']);
        if (!in_array($params['amount'], $this->amountMap)) {
            return fail('充值金额有误。只能是 30, 50, 100, 200', CODE_MOBILE_AMOUNT_ERROR);
        }

        $order = Db::name('mobile_order')
            ->field('id')
            ->where('out_order_id', $params['out_order_id'])
            ->where('agent_id', $params['agent']['id'])
            ->find();
        if (!empty($order)) {
            return fail('订单已存在', CODE_ORDER_EXISTS);
        }
        if (mb_strlen($params['out_order_id']) > 32) {
            return fail('out_order_id 不能超过 32 个字符', CODE_ERROR);
        }
        if (mb_strlen($params['notify_url']) > 100) {
            return fail('notify_url 不能超过 100 个字符', CODE_ERROR);
        }

        $ispType = getMobileIsp($params['mobile']);
        // 不同运营商，话费折扣不一样
        $config = Db::name('agent_service_config')
            ->field('discount_slow, discount_fast, discount_slow_all, discount_fast_all')
            ->where('agent_id', $params['agent']['id'])
            ->where('serv_type', PRODUCT_MOBILE_SERV)
            ->find();
        if (empty($config)) {
            return fail('产品配置异常，请联系管理员。' . __LINE__);
        }
        $config['discount_slow_all'] = json_decode($config['discount_slow_all'], true);
        $config['discount_fast_all'] = json_decode($config['discount_fast_all'], true);

        if (!empty($params['is_fast'])) {
            if (1 != $params['is_fast']) {
                return fail('is_fast 有误【' . $params['is_fast'] . '】');
            }
            // 快充
            $orderType = 2;
            $settleDiscount = $config['discount_fast_all'][$ispType] ?? $config['discount_fast'];
        } else {
            // 慢充
            $orderType = 1;
            $settleDiscount = $config['discount_slow_all'][$ispType] ?? $config['discount_slow'];
        }
        $settlePrice = intval(strval($params['amount'] * $settleDiscount));

        $salePrice = yuan2fen($params['sale_price']);
        $profit = $salePrice - $settlePrice;
        if ($profit < 0) {
            return fail('销售价格不能低于成本价');
        }
        $saleDiscount = intval(strval($params['sale_price'] / $params['amount'] * 100));

        // 筛选话费供应商 -- start
        // 指定的供应商
        $usedSupplierIds = Db::name('agent_mobile_supplier')
            ->where('agent_id', $params['agent']['id'])
            ->column('mobile_supplier_id');

        // 供应商信息
        // $supplierList = MobileSupplier::whereIn('id', $usedSupplierIds)->column('*', 'id');
        $supplierList = Db::name('mobile_supplier')
            ->whereIn('id', $usedSupplierIds)
            ->column('discount_slow, discount_fast, discount_slow_all, discount_fast_all', 'id');
        foreach ($supplierList as $k => $v) {
            $supplierList[$k]['discount_slow_all'] = json_decode($v['discount_slow_all'], true);
            $supplierList[$k]['discount_fast_all'] = json_decode($v['discount_fast_all'], true);
        }

        $map = [
            1 => 'yidong',
            2 => 'liantong',
            3 => 'dianxin',
            -1 => 'other',
        ];
        // $ispType = getMobileIsp($params['mobile']);
        $fieldName = $map[$ispType];
        if (1 == $orderType) {
            $fieldName .= '_slow';
        } else {
            $fieldName .= '_fast';
        }
        $filename = root_path() . '/data/mobileSupplierPriority.json';
        $priority = file_get_contents($filename);
        $priority = json_decode($priority, true);
        if (empty($priority) || empty($priority[$fieldName][$params['amount']])) {
            return fail('充值面额维护中');
        }
        $tmp = $priority[$fieldName][$params['amount']];
        // todo 待优化
        $supplier = [];
        foreach ($tmp as $id => $num) {
            if (!in_array($id, $usedSupplierIds)) {
                continue;
            }
            $supplier = array_merge($supplier, array_fill(0, $num, $id));
        }
        if (empty($supplier)) {
            return fail('充值通道维护中');
        }
        $max = count($supplier) - 1;
        $index = random_int(0, $max);
        $mobileSupplierId = $supplier[$index];
        unset($supplier);
        unset($priority);
        // 筛选话费供应商 -- end

        $orderId = generateMobileOrderId();
        if (false === $orderId) {
            return fail('订单号生成失败，请重试', CODE_GENERATE_ORDER_FAIL);
        }

        // 供应商折扣相关计算
        if (2 == $orderType) {
            $supplierDiscount = $supplierList[$mobileSupplierId]['discount_fast_all'][$ispType] ?? $supplierList[$mobileSupplierId]['discount_fast'];
        } else {
            $supplierDiscount = $supplierList[$mobileSupplierId]['discount_slow_all'][$ispType] ?? $supplierList[$mobileSupplierId]['discount_slow'];
        }
        $supplierPrice = intval(strval($params['amount'] * $supplierDiscount));
        $platformProfit = $settlePrice - $supplierPrice;

        // 销售价，不能低于平台成本价
        if ($salePrice <= $supplierPrice) {
            return fail('价格有误');
        }
        $salesmanId = AgentSalesman::getSalesmanIdByAgentId($params['agent']['id'], PRODUCT_MOBILE_SERV);
        Db::startTrans();
        try {
            $id = Db::name('mobile_order')
                ->insertGetId([
                    'agent_id' => $params['agent']['id'],
                    'order_id' => $orderId,
                    'sub_order_id' => $orderId,
                    'out_order_id' => $params['out_order_id'],
                    'mobile' => $params['mobile'],
                    'amount' => yuan2fen($params['amount']),
                    'status' => 1,
                    'sale_discount' => $saleDiscount,
                    'settle_discount' => $settleDiscount,
                    'sale_price' => $salePrice,
                    'settle_price' => $settlePrice,
                    'supplier_discount' => $supplierDiscount, //供应商折扣
                    'supplier_price' => $supplierPrice,
                    'platform_profit' => $platformProfit,
                    'profit' => $profit,
                    'settle_type' => $params['settle_type'],
                    'order_type' => $orderType,
                    'order_from' => ORDER_FROM_API,
                    'notify_url' => $params['notify_url'],
                    'mobile_supplier_id' => $mobileSupplierId,
                    'salesman_id' => $salesmanId,
                ]);
            if (PAY_WEIXIN == $params['pay_type']) {
                $tradeType = 'MWEB';
            } else {
                $tradeType = 'ALIPAY';
            }
            // 需要在线支付
            Db::name('pay_log')->insert([
                'agent_id' => $params['agent']['id'],
                'pay_channel' => $params['pay_type'],
                'order_id' => $orderId,
                'mobile' => $params['mobile'],
                'amount' => yuan2fen($params['amount']),
                'status' => 1,
                'sale_discount' => $saleDiscount,
                'sale_price' => $salePrice,
                'settle_discount' => $settleDiscount,
                'settle_price' => $settlePrice,
                'trade_type' => $tradeType,
                'settle_type' => $params['settle_type'],
            ]);

            Db::commit();
        } catch (\Exception $e) {
            Db::rollback();

            return fail($e->getMessage(), CODE_SYSTEM_ERROR);
        }

        return success('下单成功', [
            'order_id' => $orderId,
            'out_order_id' => $params['out_order_id'],
            'amount' => $params['amount'],
            'pay_url' => Request::domain() . '/third/pay/h5/?ak=' . $orderId,
        ]);
    }

    /**
     * 订单查询.
     */
    public function queryOrder($params)
    {
        if (empty($params['out_order_id'])) {
            return fail('缺少参数 out_order_id', CODE_MISS_PARAM);
        }

        $order = Db::name('mobile_order')
            ->field('order_id, out_order_id, mobile, amount, settle_price,
            supplier_status as status, remark')
            ->where('out_order_id', $params['out_order_id'])
            ->where('agent_id', $params['agent']['id'])
            ->find();
        if (empty($order)) {
            return fail('订单不存在', CODE_ORDER_NOT_EXISTS);
        }
        // status = 21 异常状态， status = 99 中间状态
        if ($order['status'] < 2 || in_array($order['status'], [21, 99])) {
            $order['status'] = 2;
        }
        $order['order_id'] = strval($order['order_id']);
        $order['amount'] = fen2yuan($order['amount']);
        $order['settle_price'] = fen2yuan($order['settle_price']);
        if (
            strpos($order['remark'], '下单失败') !== false
            || strpos($order['remark'], '后台手动') !== false
            || strpos($order['remark'], '余额') !== false
        ) {
            $order['remark'] = '';
        }

        return success('查询成功', $order);
    }
}
